package cn.simon.free.redis.crud.service;

import cn.simon.free.redis.component.BeanUtils;
import cn.simon.free.redis.component.RedisSupport;
import cn.simon.free.redis.crud.CommonConvert;
import cn.simon.free.redis.crud.annotations.Ro;
import cn.simon.free.redis.crud.annotations.RoField;
import cn.simon.free.redis.crud.dao.RedisCrudDao;
import cn.simon.free.redis.crud.model.BaseRo;
import com.google.common.base.Joiner;
import lombok.SneakyThrows;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * redis的crud相关操作(hash)
 *
 * @author simon
 * @date 2021/5/31 15:20
 * @copyright:
 * @modifier
 * @motto a no talent, people who have to study hard
 */
public abstract class RedisCrudService<T extends BaseRo<Id>, Id> extends CommonConvert<T> implements RedisCrudDao<T, Id> {

    @SneakyThrows
    protected RedisCrudService() {
        Ro ro = super.crudClass.getAnnotation(Ro.class);
        Assert.notNull(ro, "Annotation @Ro can't null");
        super.hashKeyPrefix = ro.key();
        super.timeOut = ro.timeOut();
        for (Field declaredField : super.crudClass.getDeclaredFields()) {
            String fieldName = declaredField.getName();
            RoField roField = declaredField.getAnnotation(RoField.class);
            if (Objects.nonNull(roField)) {
                super.hashFieldWithFieldAliasMaps.put(fieldName, roField.key());
            }
        }
    }

    @Override
    public void save(T t) {
        RedisSupport.jedisHashSupport.hmSet(hashKey(t.getId()), super.convertWithWrite(BeanUtils.beanToMap(t)));
        if (timeOut > -1) {
            RedisSupport.jedisHashSupport.setExpire(hashKey(t.getId()), timeOut);
        }
    }

    @Override
    public boolean delete(Id id) {
        return RedisSupport.jedisHashSupport.del(hashKey(id));
    }

    @Override
    public T get(Id id) {
        return super.convertWithRead(RedisSupport.jedisHashSupport.hmGetAll(hashKey(id)));
    }

    @Override
    public void update(T t) {
        save(t);
    }

    /**
     * 是否强制更新
     * 1. forceUpdate 为false会检查是否存在当前对象,如果不存在再更新,存在就跳过
     * 2. forceUpdate 为true,等价于save()方法
     *
     * @param t
     * @param forceUpdate
     */
    public void update(T t, boolean forceUpdate) {
        if (Boolean.TRUE.equals(forceUpdate)) {
            save(t);
        } else {
            boolean isExist = RedisSupport.jedisHashSupport.exists(hashKey(t.getId()));
            if (Boolean.FALSE.equals(isExist)) {
                save(t);
            }
        }
    }

    public String hashKey(Id id) {
        Assert.notNull(id, "id can't be null");
        return Joiner.on(":").skipNulls().join(hashKeyPrefix, id);
    }
}
